home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d8 / pdriver5.arc / HEAD.ASM < prev    next >
Assembly Source File  |  1989-12-17  |  18KB  |  823 lines

  1.     include    defs.asm
  2.  
  3. ;  Copyright, 1988, 1989, Russell Nelson
  4.  
  5. ;   This program is free software; you can redistribute it and/or modify
  6. ;   it under the terms of the GNU General Public License as published by
  7. ;   the Free Software Foundation, version 1.
  8. ;
  9. ;   This program is distributed in the hope that it will be useful,
  10. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. ;   GNU General Public License for more details.
  13. ;
  14. ;   You should have received a copy of the GNU General Public License
  15. ;   along with this program; if not, write to the Free Software
  16. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. code    segment byte public
  19.     assume    cs:code, ds:code
  20.  
  21.     public    phd_environ
  22.     org    2ch
  23. phd_environ    dw    ?
  24.  
  25.     public    phd_dioa
  26.     org    80h
  27. phd_dioa    label    byte
  28.  
  29.     org    100h
  30. start:
  31.     jmp    start_1
  32.     extrn    start_1: near
  33.  
  34. ;we use our dioa for a stack space.  Very hard usage has shown that only
  35. ;  27 bytes were being used, so 128 should be sufficient.
  36. our_stack    label    byte
  37.  
  38.  
  39.     extrn    int_no: byte
  40.     public    packet_int_no, is_at, sys_features
  41. packet_int_no    db    ?,?,?,?        ; interrupt to communicate.
  42. is_at        db    0        ; =1 if we're on an AT.
  43. sys_features    db    0        ; 2h = MC   40h = 2nd 8259
  44.  
  45. functions    label    word
  46.     dw    f_driver_info        ;function 1
  47.     dw    f_access_type
  48.     dw    f_release_type
  49.     dw    f_send_pkt
  50.     dw    f_terminate
  51.     dw    f_get_address
  52.     dw    f_reset_interface    ;function 7
  53.     dw    f_set_rcv_mode        ;function 20
  54.     dw    f_get_rcv_mode
  55.     dw    f_set_multicast_list
  56.     dw    f_get_multicast_list
  57.     dw    f_get_statistics
  58.     dw    f_set_address        ;function 25
  59.  
  60.  
  61.     extrn    driver_class: byte
  62.     extrn    driver_type: byte
  63.     extrn    driver_name: byte
  64.  
  65.     extrn    send_pkt: near
  66.     extrn    get_address: near
  67.     extrn    set_address: near
  68.     extrn    reset_interface: near
  69.     extrn    recv: near
  70.     extrn    recv_exiting: near
  71.  
  72.     extrn    rcv_modes: word        ;count of modes followed by mode handles.
  73.  
  74.     extrn    set_multicast_list: near
  75.     extrn    get_multicast_list: near
  76.  
  77. per_handle    struc
  78. in_use        db    ?        ;non-zero if this handle is in use.
  79. packet_type    db    MAX_P_LEN dup(?);associated packet type.
  80. packet_type_len    dw    ?        ;associated packet type length.
  81. receiver    dd    ?        ;receiver handler.
  82.         db    ?        ;padding to get the length to 16.
  83. per_handle    ends
  84.  
  85.   if (size per_handle) NE 16
  86.     err    The size of the handle must be 16.
  87.   endif
  88.  
  89. handles        db    MAX_HANDLE*(size per_handle) dup(0)
  90. end_handles    label    byte
  91.  
  92. multicast_count    dw    0        ;count of stored multicast addresses.
  93. multicast_addrs    db    MAX_MULTICAST*EADDR_LEN dup(?)
  94.  
  95. have_my_address    db    0        ;nonzero if our address has been set.
  96. my_address    db    MAX_ADDR_LEN dup(?)
  97. my_address_len    dw    ?
  98.  
  99. rcv_mode_num    dw    3
  100.  
  101. free_handle    dw    ?        ;->a handle not in use.
  102. found_handle    dw    ?        ;->the handle for our packet.
  103. receive_ptr    dd    ?        ;->the receive routine.
  104.  
  105. savess        dw    ?        ;saved during the stack swap.
  106. savesp        dw    ?
  107.  
  108. regs    struc
  109. _ES    dw    ?
  110. _DS    dw    ?
  111. _BP    dw    ?
  112. _DI    dw    ?
  113. _SI    dw    ?
  114. _DX    dw    ?
  115. _CX    dw    ?
  116. _BX    dw    ?
  117. _AX    dw    ?
  118. _IP    dw    ?
  119. _CS    dw    ?
  120. _F    dw    ?        ;flags
  121. regs    ends
  122.  
  123. CY    equ    0001h
  124. EI    equ    0200h
  125.  
  126.  
  127. bytes    struc
  128.     dw    ?
  129.     dw    ?
  130.     dw    ?
  131.     dw    ?
  132.     dw    ?
  133. _DL    db    ?
  134. _DH    db    ?
  135. _CL    db    ?
  136. _CH    db    ?
  137. _BL    db    ?
  138. _BH    db    ?
  139. _AL    db    ?
  140. _AH    db    ?
  141. bytes    ends
  142.  
  143.     public    our_isr, their_isr
  144. their_isr    dd    ?
  145.  
  146. our_isr:
  147.     jmp    our_isr_0        ;the required signature.
  148.     db    'PKT DRVR',0
  149.  
  150. statistics_list    label    dword
  151. packets_in    dw    ?,?
  152. packets_out    dw    ?,?
  153. bytes_in    dw    ?,?
  154. bytes_out    dw    ?,?
  155. errors_in    dw    ?,?
  156. errors_out    dw    ?,?
  157. packets_dropped    dw    ?,?        ;dropped due to no type handler.
  158.  
  159. linc    macro    n
  160.     local    a
  161.     inc    n            ;increment the low word
  162.     jne    a            ;go if not overflow
  163.     inc    n+2            ;increment the high word
  164. a:
  165.     endm
  166.  
  167.     public    count_in_err
  168. count_in_err:
  169.     assume    ds:nothing
  170.     linc    errors_in
  171.     ret
  172.  
  173.     public    count_out_err
  174. count_out_err:
  175.     assume    ds:nothing
  176.     linc    errors_out
  177.     ret
  178.  
  179. our_isr_0:
  180.     assume    ds:nothing
  181.     push    ax
  182.     push    bx
  183.     push    cx
  184.     push    dx
  185.     push    si
  186.     push    di
  187.     push    bp
  188.     push    ds
  189.     push    es
  190.     cld
  191.     mov    bx,cs            ;set up ds.
  192.     mov    ds,bx
  193.     assume    ds:code
  194.     mov    bp,sp            ;we use bp to access the original regs.
  195.     and    _F[bp],not CY        ;start by clearing the carry flag.
  196.     test    _F[bp],EI        ;were interrupts enabled?
  197.     jz    our_isr_ei        ;no.
  198. ;    sti                ;yes - re-enable them.
  199. our_isr_ei:
  200.     mov    dh,BAD_COMMAND        ;in case we find a bad number.
  201.     mov    bl,ah            ;jump to the correct function.
  202.     mov    bh,0
  203.     cmp    bx,7            ;highest function is 7.
  204.     jbe    our_isr_ok
  205.     cmp    bx,20
  206.     jb    our_isr_error
  207.     cmp    bx,25
  208.     ja    our_isr_error
  209.     sub    bx,20-7-1        ;map 20 right after 7.
  210. our_isr_ok:
  211.     add    bx,bx            ;*2
  212.     call    functions-2[bx]        ;table starts at 1.
  213.     jnc    our_isr_return
  214. our_isr_error:
  215.     mov    _DH[bp],dh
  216.     or    _F[bp],CY        ;return their carry flag.
  217. our_isr_return:
  218.     pop    es
  219.     pop    ds
  220.     pop    bp
  221.     pop    di
  222.     pop    si
  223.     pop    dx
  224.     pop    cx
  225.     pop    bx
  226.     pop    ax
  227.     iret
  228.  
  229.  
  230. f_driver_info:
  231. ;    Under 1.08, the handle is optional, so we no longer verify it.
  232. ;    call    verify_handle
  233.     mov    _BX[bp],majver        ;version
  234.     mov    al,driver_class
  235.     mov    _CH[bp],al
  236.     mov    al,driver_type
  237.     cbw
  238.     mov    _DX[bp],ax
  239.     mov    _CL[bp],0        ;number zero.
  240.     mov    _DS[bp],ds
  241.     mov    _SI[bp],offset driver_name
  242.     mov    _AL[bp],2        ;extended driver
  243.     clc
  244.     ret
  245.  
  246.  
  247. f_set_rcv_mode:
  248.     call    verify_handle
  249.     mov    cx,_CX[bp]        ;Tell them how much room they have.
  250.     cmp    cx,rcv_modes        ;do they have this many modes?
  251.     jae    f_set_rcv_mode_1    ;no - must be a bad mode for us.
  252.     mov    bx,cx
  253.     add    bx,bx            ;we're accessing words, not bytes.
  254.     mov    ax,rcv_modes[bx]+2    ;get the handler for this mode.
  255.     or    ax,ax            ;do they have one?
  256.     je    f_set_rcv_mode_1    ;no - must be a bad mode for us.
  257.     mov    rcv_mode_num,cx        ;yes - remember the number and
  258.     call    ax            ;  call it.
  259.     clc
  260.     ret
  261. f_set_rcv_mode_1:
  262.     mov    dh,BAD_MODE
  263.     stc
  264.     ret
  265.  
  266.  
  267. f_get_rcv_mode:
  268.     call    verify_handle
  269.     mov    ax,rcv_mode_num        ;return the current receive mode.
  270.     mov    _AX[bp],ax
  271.     clc
  272.     ret
  273.  
  274.  
  275. f_set_multicast_list:
  276. ;    mov    cx,_CX[bp]        ;Tell them how much room they have.
  277.  
  278. ;verify that they supplied an even number of EADDR's.
  279.     mov    ax,cx
  280.     xor    dx,dx
  281.     mov    bx,EADDR_LEN
  282.     div    bx
  283.     or    dx,dx            ;zero remainder?
  284.     jne    f_set_multicast_list_2
  285.  
  286.     cmp    cx,MAX_MULTICAST*EADDR_LEN    ;is this too many?
  287.     jbe    f_set_multicast_list_1
  288.     mov    cx,MAX_MULTICAST*EADDR_LEN    ;yes - store only this many.
  289. f_set_multicast_list_1:
  290.     mov    multicast_count,cx
  291.     push    cs
  292.     pop    es
  293.     mov    di,offset multicast_addrs
  294.     push    ds
  295.     mov    ds,_ES[bp]        ; get ds:si -> new list.
  296.     mov    si,_DI[bp]
  297.     rep    movsb
  298.     pop    ds
  299.  
  300.     mov    es,_ES[bp]        ; get new ones
  301.     mov    di,_DI[bp]        ; get pointer, es:di is ready
  302.     mov    cx,_CX[bp]        ;Tell them how much room they have.
  303.     call    set_multicast_list
  304.     ret
  305. f_set_multicast_list_2:
  306.     mov    dh,BAD_ADDRESS
  307.     stc
  308.     ret
  309.  
  310.  
  311. f_get_multicast_list:
  312.     call    get_multicast_list    ;Can they do it themselves?
  313.     jnc    f_get_multicast_list_1    ;yes - we're all set.
  314.     cmp    dh,NO_ERROR        ;do they implement multicast at all?
  315.     stc
  316.     jne    f_get_multicast_list_1    ;no - return an error.
  317.     mov    _ES[bp],ds        ;we have to return what we have stored.
  318.     mov    _DI[bp],offset multicast_addrs
  319.     mov    cx,multicast_count
  320.     mov    _CX[bp],cx
  321.     clc
  322. f_get_multicast_list_1:
  323.     ret
  324.  
  325.  
  326. f_get_statistics:
  327.     call    verify_handle        ;just in case.
  328.     mov    _DS[bp],ds
  329.     mov    _SI[bp],offset statistics_list
  330.     clc
  331.     ret
  332.  
  333.  
  334. access_type_class:
  335.     mov    dh,NO_CLASS
  336.     stc
  337.     ret
  338.  
  339. access_type_type:
  340.     mov    dh,NO_TYPE
  341.     stc
  342.     ret
  343.  
  344. access_type_number:
  345.     mov    dh,NO_NUMBER
  346.     stc
  347.     ret
  348.  
  349. access_type_bad:
  350.     mov    dh,BAD_TYPE
  351.     stc
  352.     ret
  353.  
  354. access_type_space:
  355.     mov    dh,NO_SPACE
  356.     stc
  357.     ret
  358.  
  359. f_access_type:
  360.     mov    al,driver_class
  361.     cmp    _AL[bp],al        ;our class?
  362.     jne    access_type_class    ;no.
  363.     cmp    _BX[bp],-1        ;generic type?
  364.     je    access_type_2        ;yes.
  365.     mov    al,driver_type
  366.     cbw
  367.     cmp    _BX[bp],ax        ;our type?
  368.     jne    access_type_type    ;no.
  369. access_type_2:
  370.     cmp    _DL[bp],0        ;generic number?
  371.     je    access_type_3
  372.     cmp    _DL[bp],1        ;our number?
  373.     jne    access_type_number
  374. access_type_3:
  375.     cmp    _CX[bp],MAX_P_LEN    ;is the type length too long?
  376.     ja    access_type_bad        ;yes - can't be ours.
  377. access_type_7:
  378.  
  379. ; now we do two things--look for an open handle, and check the existing
  380. ; handles to see if they're replicating a packet type.
  381.  
  382.     mov    free_handle,0        ;remember no free handle yet.
  383.     mov    bx,offset handles
  384. access_type_4:
  385.     cmp    [bx].in_use,0        ;is this handle in use?
  386.     je    access_type_5        ;no - don't check the type.
  387.     mov    es,_DS[bp]        ;get a pointer to their type.
  388.     mov    di,_SI[bp]
  389.     mov    cx,_CX[bp]        ;get the minimum of their length
  390.                     ;  and our length.  As currently
  391.                     ;  implemented, only one receiver
  392.                     ;  gets the packets, so we have to
  393.                     ;  ensure that the shortest prefix
  394.                     ;  is unique.
  395.     cmp    cx,[bx].packet_type_len    ;Are we less specific than they are?
  396.     jb    access_type_8        ;no.
  397.     mov    cx,[bx].packet_type_len    ;yes - use their count.
  398. access_type_8:
  399.     lea    si,[bx].packet_type
  400.     or    cx,cx            ;in case cx is zero.
  401.     repe    cmpsb
  402.     jne    short access_type_6    ;go look at the next one.
  403. access_type_inuse:
  404.     mov    dh,TYPE_INUSE
  405.     stc
  406.     ret
  407. access_type_5:
  408.     cmp    free_handle,0        ;found a free handle yet?
  409.     jne    access_type_6        ;yes.
  410.     mov    free_handle,bx        ;remember a free handle
  411. access_type_6:
  412.     add    bx,(size per_handle)    ;go to the next handle.
  413.     cmp    bx,offset end_handles
  414.     jb    access_type_4
  415.  
  416.     mov    bx,free_handle        ;did we find a free handle?
  417.     or    bx,bx
  418.     je    access_type_space    ;no - return error.
  419.  
  420.     mov    [bx].in_use,1        ;remember that we're using it.
  421.  
  422.     mov    ax,_DI[bp]        ;remember the receiver type.
  423.     mov    [bx].receiver.offs,ax
  424.     mov    ax,_ES[bp]
  425.     mov    [bx].receiver.segm,ax
  426.  
  427.     push    ds
  428.     mov    ax,ds
  429.     mov    es,ax
  430.     mov    ds,_DS[bp]        ;remember their type.
  431.     mov    si,_SI[bp]
  432.     mov    cx,_CX[bp]
  433.     mov    es:[bx].packet_type_len,cx    ;remember the length.
  434.     lea    di,[bx].packet_type
  435.     rep    movsb
  436.     pop    ds
  437.  
  438.     sub    bx,offset handles    ;compute the handle from the offset.
  439.     mov    cl,4
  440.     shr    bx,cl
  441.     mov    ax,cs            ;add our phd in.
  442.     add    bx,ax
  443.     mov    _AX[bp],bx        ;return the handle to them.
  444.  
  445.     clc
  446.     ret
  447.  
  448.  
  449. f_release_type:
  450.     call    verify_handle        ;mark this handle as being unused.
  451.     mov    [bx].in_use,0
  452.     clc
  453.     ret
  454.  
  455.  
  456. f_send_pkt:
  457.     linc    packets_out
  458.     add    bytes_out.offs,cx    ;add up the received bytes.
  459.     adc    bytes_out.segm,0
  460.  
  461.     push    ds        ; set up proper ds for the buffer
  462.     mov    ds,_DS[bp]    ; address for buffer
  463. ;following two instructions not needed because si and cx haven't been changed.
  464. ;    mov    si,_SI[bp]
  465. ;    mov    cx,_CX[bp]    ; count of bytes
  466.  
  467.     call    send_pkt
  468.     pop    ds
  469.     ret
  470.  
  471.  
  472. f_terminate:
  473. ;
  474. ; Now disable interrupts
  475. ;
  476.     mov    al,int_no
  477.     call    maskint
  478.  
  479. ;
  480. ; Now return the interrupt to their handler.
  481. ;
  482.     mov    ah,25h            ;get the old interrupt into es:bx
  483.     mov    al,int_no
  484.     add    al,8
  485.     cmp    al,8+8            ;is it a slave 8259 interrupt?
  486.     jb    terminate_1        ;no.
  487.     add    al,70h - (8+8)        ;map it to the real interrupt.
  488. terminate_1:
  489.     push    ds
  490.     lds    dx,their_recv_isr
  491.     int    21h
  492.     pop    ds
  493.  
  494.     mov    al,packet_int_no    ;release our_isr.
  495.     mov    ah,25h
  496.     push    ds
  497.     lds    dx,their_isr
  498.     int    21h
  499.     pop    ds
  500.  
  501. ;
  502. ; Now free our memory
  503. ;
  504.     push    cs
  505.     pop    es
  506.     mov    ah,49h
  507.     int    21h
  508.  
  509.     clc
  510.     ret
  511.  
  512.  
  513. f_get_address:
  514.     call    verify_handle
  515. ;    mov    es,_ES[bp]        ; get new one
  516. ;    mov    di,_DI[bp]        ; get pointer, es:di is ready
  517.     mov    cx,_CX[bp]        ;Tell them how much room they have.
  518.     cmp    have_my_address,0    ;Did we get our address set?
  519.     jne    get_address_set
  520.     call    get_address
  521.     jc    get_address_space    ;no.
  522.     mov    _CX[bp],cx        ;Tell them how long our address is.
  523.     clc
  524.     ret
  525. get_address_set:
  526.     cmp    cx,my_address_len    ;is there enough room?
  527.     jb    get_address_space    ;no.
  528.     mov    cx,my_address_len    ;yes - get our address length.
  529.     mov    _CX[bp],cx        ;Tell them how long our address is.
  530.     mov    si,offset my_address    ;copy it into their area.
  531.     rep    movsb
  532.     clc
  533.     ret
  534.  
  535. get_address_space:
  536.     mov    dh,NO_SPACE
  537.     stc
  538.     ret
  539.  
  540.  
  541. f_set_address:
  542.     mov    bx,offset handles
  543.     mov    dh,CANT_SET        ;if a handle in use, we can't set it.
  544. f_set_address_1:
  545.     cmp    [bx].in_use,0        ;is this handle in use?
  546.     stc
  547.     jne    f_set_address_exit    ;yes - we can't set the address
  548.     add    bx,(size per_handle)    ;go to the next handle.
  549.     cmp    bx,offset end_handles
  550.     jb    f_set_address_1
  551.  
  552.     mov    ds,_ES[bp]        ; set new one
  553.     assume    ds:nothing
  554.     mov    si,_DI[bp]        ; set pointer, ds:si is ready
  555. ;    mov    cx,_CX[bp]        ;Tell them how much address is being set.
  556.     call    set_address
  557. ;set_address restores ds.
  558.     jc    f_set_address_exit    ;Did it work?
  559.     mov    _CX[bp],cx        ;yes - return our address length.
  560.  
  561.     cmp    cx,MAX_ADDR_LEN        ;is it too long for us to remember?
  562.     ja    f_set_address_too_long    ;yes, return a too-long error.
  563.  
  564.     mov    ds,_ES[bp]        ; set new one
  565.     mov    si,_DI[bp]        ; set pointer, ds:si is ready
  566.     mov    ax,cs
  567.     mov    es,ax
  568.     mov    my_address_len,cx    ;remember how long our address is.
  569.     mov    di,offset my_address
  570.     rep    movsb
  571.     mov    have_my_address,1
  572.     mov    ds,ax            ;restoer ds.
  573.     assume    ds:code
  574.     clc
  575.     jmp    short f_set_address_exit
  576.  
  577. f_set_address_too_long:
  578.     mov    dh,NO_SPACE
  579.     stc
  580. f_set_address_exit:
  581.     ret
  582.  
  583.  
  584. f_reset_interface:
  585.     call    verify_handle
  586.     call    reset_interface
  587.     clc
  588.     ret
  589.  
  590.  
  591. compute_handle:
  592. ;enter with the external representation of our handle in _BX[bp],
  593. ;exit with the offset of the handle in bx.
  594.     mov    bx,_BX[bp]        ;get the handle they gave us
  595.     mov    cx,cs
  596.     sub    bx,cx            ;subtract off our phd
  597.     mov    cl,4
  598.     shl    bx,cl            ;multiply by the size of the struct,
  599.     add    bx,offset handles    ;  and add the offset of the table.
  600.     ret
  601.  
  602.  
  603. verify_handle:
  604. ;Ensure that their handle is real.  If it isn't, we pop off our return
  605. ;address, and return to *their* return address with cy set.
  606.     call    compute_handle
  607.     cmp    bx,offset handles
  608.     jb    verify_handle_bad    ;no - must be bad.
  609.     cmp    bx,offset end_handles
  610.     jae    verify_handle_bad    ;no - must be bad.
  611.     cmp    [bx].in_use,0        ;if it's not in use, it's bad.
  612.     je    verify_handle_bad
  613.     ret
  614. verify_handle_bad:
  615.     mov    dh,BAD_HANDLE
  616.     add    sp,2            ;pop off our return address.
  617.     stc
  618.     ret
  619.  
  620.  
  621.     public    set_recv_isr
  622. set_recv_isr:
  623.     mov    ah,35h            ;get the old interrupt into es:bx
  624.     mov    al,int_no
  625.     add    al,8
  626.     cmp    al,8+8            ;is it a slave 8259 interrupt?
  627.     jb    set_recv_isr_1        ;no.
  628.     add    al,70h - 8 - 8        ;map it to the real interrupt.
  629. set_recv_isr_1:
  630.     int    21h
  631.     mov    their_recv_isr.offs,bx
  632.     mov    their_recv_isr.segm,es
  633.  
  634.     mov    ah,25h            ;now set our recv interrupt.
  635.     mov    dx,offset recv_isr
  636.     int    21h
  637. ;
  638. ; Now enable interrupts
  639. ;
  640.     mov    al,int_no
  641.     call    unmaskint
  642.  
  643.     ret
  644.  
  645. their_recv_isr    dd    ?
  646.  
  647. recv_isr:
  648.     push    ax
  649.     push    ds
  650.     mov    ax,cs            ;ds = cs.
  651.     mov    ds,ax
  652.  
  653.     mov    savesp,sp
  654.     mov    savess,ss
  655.  
  656.     mov    ss,ax
  657.     mov    sp,offset our_stack
  658.     cld
  659.     sti
  660.  
  661.     push    bx
  662.     push    cx
  663.     push    dx
  664.     push    si
  665.     push    di
  666.     push    bp
  667.     push    es
  668.  
  669.     call    recv
  670.  
  671.     cli                ;interrupts *must* be off between
  672.                     ;here and the stack restore, because
  673.                     ;if we have one of our interrupts
  674.                     ;pending, we would trash our stack.
  675. ;
  676. ; The following code is ruthlessly stolen from Phil Karn's NET package.
  677. ;
  678.     test    sys_features,40h ; 2nd 8259 installed?
  679.     jz    recv_isr_3    ; Only one 8259, so skip this stuff
  680.     mov    al,0bh        ; read in-service register from
  681.     out    0a0h,al        ; secondary 8259
  682.     nop            ; settling delay
  683.     nop
  684.     nop
  685.     in    al,0a0h        ; get it
  686.     or    al,al        ; Any bits set?
  687.     jz    recv_isr_3    ; nope, not a secondary interrupt
  688.     mov    al,20h        ; Get EOI instruction
  689.     out    0a0h,al        ; Secondary 8259 (PC/AT only)
  690. recv_isr_3:
  691.     mov    al,20h            ;acknowledge the interrupt.
  692.     out    20h,al
  693.  
  694.     pop    es
  695.     pop    bp
  696.     pop    di
  697.     pop    si
  698.     pop    dx
  699.     pop    cx
  700.     pop    bx
  701.  
  702.     mov    ss,savess
  703.     mov    sp,savesp
  704.  
  705.     call    recv_exiting        ;this routine can enable interrupts.
  706.  
  707.     pop    ds
  708.     pop    ax
  709.     iret
  710.  
  711.  
  712. maskint:
  713.     mov    dx,21h            ;assume the master 8259.
  714.     cmp    al,8            ;using the slave 8259 on an AT?
  715.     jb    mask_not_irq2
  716.     mov    dx,0a1h            ;go enable it on slave 8259
  717.     sub    al,8
  718. mask_not_irq2:
  719.     mov    cl,al
  720.  
  721.     in    al,dx            ;enable interrupts on the correct 8259.
  722.     mov    ah,1            ;set the bit.
  723.     shl    ah,cl
  724.     or    al,ah
  725.     out    dx,al
  726.  
  727.     ret
  728.  
  729.  
  730. unmaskint:
  731.     mov    dx,21h            ;assume the master 8259.
  732.     cmp    al,8            ;using the slave 8259 on an AT?
  733.     jb    unmask_not_irq2
  734.     mov    dx,0a1h            ;go enable it on slave 8259
  735.     sub    al,8
  736. unmask_not_irq2:
  737.     mov    cl,al
  738.  
  739.     in    al,dx            ;enable interrupts on the correct 8259.
  740.     mov    ah,1            ;clear the bit.
  741.     shl    ah,cl
  742.     not    ah
  743.     and    al,ah
  744.     out    dx,al
  745.  
  746.     ret
  747.  
  748.  
  749.     public    recv_find
  750. recv_find:
  751. ;called when we want to determine what to do with a received packet.
  752. ;enter with cx = packet length, es:di -> packet type.
  753.     assume    ds:code, es:nothing
  754.     push    cx
  755.  
  756.     mov    bx,offset handles
  757. recv_find_1:
  758.     cmp    [bx].in_use,0        ;is this handle in use?
  759.     je    recv_find_2        ;no - don't check the type.
  760.     mov    ax,[bx].receiver.offs    ;do they have a receiver?
  761.     or    ax,[bx].receiver.segm
  762.     je    recv_find_2        ;no - they're not serious about it.
  763.     mov    cx,[bx].packet_type_len    ;compare the packets.
  764.     lea    si,[bx].packet_type
  765.     or    cx,cx            ;in case cx is zero.
  766.     push    di
  767.     repe    cmpsb
  768.     pop    di
  769.     je    recv_find_3        ;we've got it!
  770. recv_find_2:
  771.     add    bx,(size per_handle)    ;go to the next handle.
  772.     cmp    bx,offset end_handles
  773.     jb    recv_find_1
  774.  
  775.     linc    packets_dropped
  776.  
  777.     pop    cx            ;we didn't find it -- discard it.
  778.     xor    di,di            ;"return" a null pointer.
  779.     mov    es,di
  780.     jmp    short recv_find_4
  781. recv_find_3:
  782.     pop    cx            ; the packet_length
  783.  
  784.     linc    packets_in
  785.     add    bytes_in.offs,cx    ;add up the received bytes.
  786.     adc    bytes_in.segm,0
  787.  
  788.     mov    ax,[bx].receiver.offs
  789.     mov    receive_ptr.offs,ax
  790.     mov    ax,[bx].receiver.segm
  791.     mov    receive_ptr.segm,ax
  792.  
  793.     sub    bx,offset handles    ;compute the handle number from
  794.     shr    bx,1            ;  the handle offset.
  795.     shr    bx,1
  796.     shr    bx,1
  797.     shr    bx,1
  798.     mov    ax,cs            ;add our phd in.
  799.     add    bx,ax
  800.  
  801.     mov    found_handle,bx        ;remember what our handle was.
  802.     mov    ax,0            ;allocate request.
  803.     call    receive_ptr        ;ask the client for a buffer.
  804. recv_find_4:
  805.     ret
  806.  
  807.  
  808.     public    recv_copy
  809. recv_copy:
  810. ;called after we have copied the packet into the buffer.
  811. ;enter with ds:si ->the packet, cx = length of the packet.
  812.     assume    ds:nothing, es:nothing
  813.     push    bx
  814.     mov    bx,found_handle
  815.     mov    ax,1            ;store request.
  816.     call    receive_ptr        ;ask the client for a buffer.
  817.     pop    bx
  818.     ret
  819.  
  820. code    ends
  821.  
  822.     end    start
  823.